package cube.utils.db.query;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import cube.utils.StringUtil;
import cube.utils.comp.Order;

/**
 * 根据条件生成Hql语句工具
 * 
 * @author abiao
 */
public class HqlGen {

    /**
     * 根据条件生成Hql语句
     */
    public static String genHql(String model, Conditions conditions,
            String orderProp, Order order) {
        StringBuffer sb = new StringBuffer();
        sb.append(genHql(model, conditions));
        contactOrderSentences(sb, model, orderProp, order);
        return sb.toString();
    }

    /**
     * 根据条件生成Hql语句
     */
    public static String genHql(String model, Conditions conditions) {
        StringBuffer sb = new StringBuffer();
        contactSelectSentence(sb, model);
        if (conditions != null) {
            contactConditionSentence(sb, model, conditions);
        }
        return sb.toString();
    }

    /**
     * 连接条件语句
     */
    private static void contactConditionSentence(StringBuffer sb, String model,
            Conditions conditions) {
        List<Condition> conditionList = conditions.getConditionList();
        if (conditionList != null) {
            contactJoinSentence(sb, conditionList);
            contactConditionSentences(sb, model, conditionList);
        }
    }

    /**
     * 连接排序语句
     */
    private static void contactOrderSentences(StringBuffer sb, String model,
            String orderProp, Order order) {
        sb.append(" order by " + model.toLowerCase() + "." + orderProp + " "
                + order);
    }

    /**
     * 连接所有条件语句
     */
    private static void contactConditionSentences(StringBuffer sb,
            String model, List<Condition> conditions) {
        sb.append(" where 1=1");
        for (int i = 0; i < conditions.size(); i++) {
            contactCondition(sb, model, conditions.get(i));
        }
    }

    /**
     * 连接条件语句
     */
    private static void contactCondition(StringBuffer sb, String model,
            Condition condition) {
        concactPropName(sb, model, condition);

        if (condition.relation == Relation.LK) {
            Object value = condition.propValue;
            if (value != null) {
                value = value.toString().replace("'", "''");
            }
            sb.append(condition.relation + " '%" + value + "%'");
        } else {
            sb.append(condition.relation + " " + condition.propValue);
            if (condition.relation == Relation.NE
                    && null != condition.propValue) {
                sb.append(" or " + model.toLowerCase() + ".");
                sb.append(condition.propName + " is null");
            }
        }
        sb.append(" )");
    }

    /**
     * 连接查询属性名
     */
    private static void concactPropName(StringBuffer sb, String model,
            Condition condition) {
        sb.append(" and ( ");
        if (isJoinRetrieve(getParams(condition.propName))) {
            sb.append(getJoinPropName(condition.propName));
        } else {
            sb.append(model.toLowerCase() + "." + condition.propName);
        }
        sb.append(" ");
    }

    /**
     * 获取连接属性名
     */
    private static String getJoinPropName(String propName) {
        String[] params = getParams(propName);
        return params[1].toLowerCase() + "." + params[2];
    }

    /**
     * 连接select语句
     */
    private static void contactSelectSentence(StringBuffer sb, String model) {
        sb.append("select " + model.toLowerCase() + " from " + model + " "
                + model.toLowerCase());
    }

    /**
     * 连接join语句
     */
    private static void contactJoinSentence(StringBuffer sb,
            List<Condition> conditions) {
        String[] uniqJoinNames = getUniqJoinNames(conditions);
        for (int i = 0; i < uniqJoinNames.length; i++) {
            sb.append(" left join " + uniqJoinNames[i]);
        }
    }

    /**
     * 属性名分割
     */
    private static String[] getParams(String propName) {
        return propName.split("\\.");
    }

    /**
     * 获取关联别名
     * 
     * @param params
     *            String[]
     * @return String
     */
    private static String getJoinAlias(String[] params) {
        return params[0].toLowerCase() + "." + params[1] + " "
                + params[1].toLowerCase();
    }

    /**
     * 是否关联查询
     * 
     * @param params
     *            String[]
     * @return boolean
     */
    private static boolean isJoinRetrieve(String[] params) {
        return params.length == 3 && params[0].charAt(0) >= 'A'
                && params[0].charAt(0) <= 'Z';
    }

    /**
     * 获取去重后的连接名
     * 
     * @param conditions
     *            Condition[]
     * @return columnNames
     */
    private static String[] getUniqJoinNames(List<Condition> conditions) {
        Set<String> joinSet = new HashSet<String>();

        for (int i = 0; i < conditions.size(); i++) {
            String[] params = getParams(conditions.get(i).propName);
            if (isJoinRetrieve(params)) {
                joinSet.add(getJoinAlias(params));
            }
        }
        return StringUtil.collection2Array(joinSet);
    }
}
